package com.yxinmiracle.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.util.ArrayBuilders;
import com.yxinmiracle.goods.feign.SkuFeign;
import com.yxinmiracle.goods.pojo.Sku;
import com.yxinmiracle.search.dao.SkuEsMapper;
import com.yxinmiracle.search.pojo.SkuInfo;
import com.yxinmiracle.search.service.SearchResultMapperImpl;
import com.yxinmiracle.search.service.SkuService;
import entity.Result;
import io.swagger.models.auth.In;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @version 1.0
 * @author： YxinMiracle
 * @date： 2021-08-12 11:09
 */
@Service
public class SkuServiceImpl implements SkuService {
    @Autowired
    private SkuFeign skuFeign;

    @Autowired
    private SkuEsMapper skuEsMapper;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Override
    public void importSku() {
        Result<List<Sku>> result = skuFeign.findByStatus("1");
        List<Sku> skuList = result.getData();
        String string = JSON.toJSONString(skuList);
        List<SkuInfo> skuInfoList = JSON.parseArray(string, SkuInfo.class);
        for (SkuInfo skuInfo : skuInfoList) {
            String spec = skuInfo.getSpec();
            Map<String, Object> SpecMap = JSON.parseObject(spec, Map.class);
            skuInfo.setSpecMap(SpecMap);
        }
        skuEsMapper.saveAll(skuInfoList);
    }

    @Override
    public Map<String, Object> search(Map<String, String> searchMap) {
        // 1.根据关键字来搜索
        String keywords = searchMap.get("keywords");
        if (StringUtils.isEmpty(keywords)){
            keywords="华为";
        }
        // 创建查询对象
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        // 1.设置分组查询的条件，商品分类的分组
        // AggregationBuilders.terms("skuCategoryGroup") 设置分组的别名
        // field("categoryName") 表示分组的字段
        // .size(10) 桶的大小
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategoryGroup").field("categoryName").size(100));
        // 品牌名字进行分组
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuBrandGroup").field("brandName").size(100));
        // 规格查询
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuSpecGroup").field("spec.keyword").size(100));

        // 高亮设置
        nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field("name"));
        nativeSearchQueryBuilder.withHighlightBuilder(new HighlightBuilder().preTags("<span style=\"color: red\">").postTags("</span>"));

        // =================================================过滤查询=============================================
        // 设置查询条件 matchQuery
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//        nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("name",keywords));
        nativeSearchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery(keywords,"name","categoryName","brandName"));
        // 布尔查询

        // filter和must的区别
        // filter仅仅只是过滤，不会根据文档分数进行排名，那么效率就会高一点
        String category = searchMap.get("category");
        if(!StringUtils.isEmpty(category)){
            TermQueryBuilder categoryName = QueryBuilders.termQuery("categoryName", category);
            boolQueryBuilder.must(categoryName);
        }

        // 品牌过滤
        String brand = searchMap.get("brand");
        if(!StringUtils.isEmpty(brand)){
            TermQueryBuilder brandName = QueryBuilders.termQuery("brandName", brand);
            boolQueryBuilder.must(brandName);
        }

        // 规格过滤
        for (Map.Entry<String, String> stringStringEntry : searchMap.entrySet()) {
            String key = stringStringEntry.getKey();
            String value = stringStringEntry.getValue();
            if (key.startsWith("spec_")){
                TermQueryBuilder GuiGeName = QueryBuilders.termQuery("specMap."+key.substring(5)+".keyword", value);
                boolQueryBuilder.must(GuiGeName);
            }
        }


        // 加个区间过滤
        String price = searchMap.get("price");
        if(!StringUtils.isEmpty(price)){
            RangeQueryBuilder rangeQueryBuilder = null;
            String[] split = price.split("-");
            if (split[1].equals("*")){
                rangeQueryBuilder = QueryBuilders.rangeQuery("price").gte(split[0]);
            }else {
                rangeQueryBuilder = QueryBuilders.rangeQuery("price").gte(split[0]).lte(split[1]);
            }
            boolQueryBuilder.filter(rangeQueryBuilder);
        }
        nativeSearchQueryBuilder.withFilter(boolQueryBuilder);


        // 分页
        Integer pageNum = 1;
        Integer pageSize = 10;
        String pageNumString = searchMap.get("pageNum");
        if(!StringUtils.isEmpty(pageNumString)){
            pageNum = Integer.valueOf(pageNumString);
        }

        Pageable pageable = PageRequest.of(pageNum-1,pageSize);
        nativeSearchQueryBuilder.withPageable(pageable);


        // 排序
        String sortField = searchMap.get("sortField");
        String sortRule = searchMap.get("sortRule");
        if(!StringUtils.isEmpty(sortField) && !StringUtils.isEmpty(sortRule)){
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("price").order(sortRule.equals("DESC")?SortOrder.DESC:SortOrder.ASC));
        }

        SearchQuery query = nativeSearchQueryBuilder.build();


        // 进行查询
        AggregatedPage<SkuInfo> skuPages = elasticsearchTemplate.queryForPage(query, SkuInfo.class, new SearchResultMapperImpl());
        List<SkuInfo> content = skuPages.getContent();
        long totalElements = skuPages.getTotalElements();
        int totalPages = skuPages.getTotalPages();

        List<String> categoryList = getGoodsList("skuCategoryGroup",skuPages);

        List<String> brandList = getGoodsList("skuBrandGroup",skuPages);

        // 规格数据清理
        StringTerms stringTermsSpec = (StringTerms) skuPages.getAggregation("skuSpecGroup");
        Map<String, Set<String>> specMap = getStringSetMap(stringTermsSpec);

        // 数据的返回
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("rows",content);
        resultMap.put("total",totalElements);
        resultMap.put("totalPages",totalPages);
        resultMap.put("categoryList",categoryList);
        resultMap.put("brandList",brandList);
        resultMap.put("specMap",specMap);
        resultMap.put("pageNum",pageNum);
        resultMap.put("pageSize",pageSize);
        return resultMap;
    }

    // todo
    private Map<String, Set<String>> getStringSetMap(StringTerms stringTerms){
        Map<String, Set<String>> specMap = new HashMap<>();
        if (stringTerms!=null){
            for (StringTerms.Bucket bucket : stringTerms.getBuckets()) {
                String keyAsString = bucket.getKeyAsString();
                Map<String, String> map = JSON.parseObject(keyAsString, Map.class);
                for (Map.Entry<String, String> stringSetEntry : map.entrySet()) {
                    String key = stringSetEntry.getKey();
                    String strings = stringSetEntry.getValue();
                    if (specMap.get(key)!=null){
                        Set<String> innerSet = specMap.get(key);
                        innerSet.add(strings);
                        specMap.put(key,innerSet);
                    }else {
                        Set<String> set = new HashSet<>();
                        set.add(strings);
                        specMap.put(key,set);
                    }
                }
            }
        }
        return specMap;
    }

    private List<String> getGoodsList(String searchGroupName,AggregatedPage<SkuInfo> skuInfos){
        List<String> ret = new ArrayList<>();
        StringTerms stringTerms = (StringTerms) skuInfos.getAggregation(searchGroupName);
        if (stringTerms!=null){
            for (StringTerms.Bucket bucket : stringTerms.getBuckets()) {
                ret.add(bucket.getKeyAsString());
            }
        }
        return ret;
    }

}
